package geldautomat;

import java.awt.Button;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JOptionPane;

import mware_lib.ObjectBroker;

import cash_access.Account;
import cash_access.OverdraftException;

/**
 * GUI-based main Application of the automat teller machine (ATM)
 * 
 */
public class Geldautomat extends Frame implements ActionListener {
	private static final long serialVersionUID = 6751599359033886260L;
	// Text fields
	private TextField KontoTextField, 
			KontostandTextField, BetragsTextField, 
			EmpfKontoTextField, BankCodeTextField;
	// Buttons
	private Button EinzahlenButton, AbhebenButton, 
			KStandAktualisierenButton, UeberweisenButton, SerienEinzahlenButton;
	// Status bar
	private StatusLine StatusLabel;
	private static String DoneMessage = "Done.";
	
	private int AnzSerienEinzahlung;
	
	private String host;
	private int port;	
	
	/**
	 * Status bar of the window
	 */
	private class StatusLine extends Label {
		private static final long serialVersionUID = -1575611930399336962L;

		public StatusLine(String text) {
			super(text);
		}
		/**
		 * for normal text
		 * 
		 * @param message
		 */
		public void setInfoText(String message) {
			setForeground(Color.BLUE);
			setText(message);
		}
		
		/**
		 * For error text.
		 * 
		 * @param message
		 */
		public void setErrorText(String message) {
			setForeground(Color.RED);
			setText(message);
		}
	}
	
	/**
	 * Constructor.
	 * Construction of the GUI.
	 *
	 */
	public Geldautomat(String host, int port) {
		super("Bancomat");
		this.host = host;
		this.port = port;
		
		AnzSerienEinzahlung = 200;
		
		//--- Layout manager
		GridBagConstraints constraints=new GridBagConstraints();
		GridBagLayout gridbag=new GridBagLayout();
		setLayout(gridbag);
		
		//--- Kontoeingabefeld
		Label KontoLabel = new Label("Konto:       ");
		constraints.insets=new Insets(10,20,5,20);
		constraints.anchor = GridBagConstraints.WEST;
		constraints.gridwidth=GridBagConstraints.RELATIVE;
		gridbag.setConstraints(KontoLabel, constraints);
		add(KontoLabel);
		
		KontoTextField = new TextField(20);
		constraints.gridwidth=GridBagConstraints.REMAINDER;
		gridbag.setConstraints(KontoTextField, constraints);
		add(KontoTextField);
		
		//--- (Separator) ------------------------
		Label separatorLabel1 = new Label("----------------------------------------------");
		constraints.insets=new Insets(5,20,5,20);
		gridbag.setConstraints(separatorLabel1, constraints);
		add(separatorLabel1);
		
		//--- Balance field
		Label KontostandLabel = new Label("Kontostand:");
		constraints.insets=new Insets(5,20,5,20);
		constraints.gridwidth=GridBagConstraints.RELATIVE;
		gridbag.setConstraints(KontostandLabel, constraints);
		add(KontostandLabel);
		
		KontostandTextField = new TextField(20);
		KontostandTextField.setEditable(false);
		constraints.gridwidth=GridBagConstraints.REMAINDER;
		gridbag.setConstraints(KontostandTextField, constraints);
		add(KontostandTextField);
		
		//--- Operation: update the balance
		KStandAktualisierenButton = new Button("aktualisieren");
		constraints.gridwidth=GridBagConstraints.REMAINDER;
		constraints.anchor = GridBagConstraints.EAST;
		gridbag.setConstraints(KStandAktualisierenButton, constraints);
		add(KStandAktualisierenButton);
		KStandAktualisierenButton.addActionListener(this);
		
		//--- (Separator) ------------------------
		Label separatorLabel2 = new Label("----------------------------------------------");
		constraints.insets=new Insets(5,20,5,20);
		constraints.anchor = GridBagConstraints.WEST;
		gridbag.setConstraints(separatorLabel2, constraints);
		add(separatorLabel2);
		
		//--- Amount field
		Label BetragsLabel = new Label("Amount:       ");
		constraints.insets=new Insets(10,20,5,20);
		constraints.gridwidth=GridBagConstraints.RELATIVE;
		gridbag.setConstraints(BetragsLabel, constraints);
		add(BetragsLabel);
		
		BetragsTextField = new TextField(20);
		constraints.gridwidth=GridBagConstraints.REMAINDER;
		gridbag.setConstraints(BetragsTextField, constraints);
		add(BetragsTextField);
		
		//--- Operation: Deposit
		EinzahlenButton = new Button("Deposit");
		EinzahlenButton.addActionListener(this);
		
		//--- Operation: Withdraw
		AbhebenButton = new Button("Withdraw");
		AbhebenButton.addActionListener(this);
		
		//--- Operation: Serial deposit
		SerienEinzahlenButton = new Button(AnzSerienEinzahlung + " x Einzahlen");
		SerienEinzahlenButton.addActionListener(this);
		
		//--- Panel Deposit/Withdraw
		Panel OpPanel1 = new Panel();
		OpPanel1.setLayout(new FlowLayout());
		OpPanel1.add(EinzahlenButton);
		OpPanel1.add(SerienEinzahlenButton);
		OpPanel1.add(AbhebenButton);
		constraints.gridwidth=GridBagConstraints.REMAINDER;
		constraints.anchor = GridBagConstraints.EAST;
		gridbag.setConstraints(OpPanel1, constraints);
		add(OpPanel1);
		
		//--- Status field
		StatusLabel = new StatusLine("                                                                      ");
		constraints.insets=new Insets(20,20,20,20);
		gridbag.setConstraints(StatusLabel, constraints);
		add(StatusLabel);


		/************ Close button *************/
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		
		pack();
	}

	/**
	 * Here the actual actions are treated.
	 */
	public void actionPerformed(ActionEvent e) {
		StatusLabel.setInfoText("");
		
		if (e.getSource() == KStandAktualisierenButton) {
			//- Pruefung des Kontofeldinhalts
			String kontoID = KontoTextField.getText();
			if (kontoID == null || kontoID.equals("")) 
				StatusLabel.setErrorText("Kontofeld leer bzw. null");
			else {

				/*---------------------------------------------
				 * Ask for the state of the Account
				 * 
				 * --------------------------------------------
				 */
				try{
				Account account = (Account) ObjectBroker.getBroker(host, port).getNameService().resolve(kontoID);
				double balance = account.getBalance();
				
				// Update the display of the balance in the GUI:
				KontostandTextField.setText(balance + "");
				
				StatusLabel.setInfoText(DoneMessage);
				}catch(Exception ex){
					StatusLabel.setErrorText("Error");
					new JOptionPane().showMessageDialog(null, "Exception: " + ex.getMessage(),"Error",
							JOptionPane.ERROR_MESSAGE);
				}
			}
		}
		else if (e.getSource() == EinzahlenButton) {
			try {
				//Amount to be paid
				double betrag = Double.parseDouble(BetragsTextField.getText());
				
				//- Test of the Account field content
				String kontoID = KontoTextField.getText();
				if (kontoID == null || kontoID.equals("")) 
					StatusLabel.setErrorText("Kontofeld leer bzw. null");
				else if(betrag < 0)
					StatusLabel.setErrorText("Betrag ist negativ");
				else {
					
					/*-----------------------------
					 * Einzahlen veranlassen
					 * ----------------------------
					 */
					try
                    {
                        Account account = (Account) ObjectBroker.getBroker(host, port).getNameService().resolve(kontoID);
                        account.deposit(betrag);

                        double bal = account.getBalance();

                        // Kontostandanzeige in GUI aktualisieren:
                        KontostandTextField.setText(bal + "");

                        StatusLabel.setInfoText(DoneMessage);
                    }
                    catch (Exception exc)
                    {
                    	StatusLabel.setErrorText("Error");
                    }
					
				}
			} catch (NumberFormatException e1) {
				StatusLabel.setErrorText("Ungueltiger Betrag!");				
			}
		}
		else if (e.getSource() == SerienEinzahlenButton)
        {
            try
            {
                // Einzuzahlender Betrag
                double betrag = Double.parseDouble(BetragsTextField.getText());

                // - Pruefung des Kontofeldinhalts
                String kontoID = KontoTextField.getText();
                if (kontoID == null || kontoID.equals(""))
                    StatusLabel.setErrorText("Kontofeld leer bzw. null");
                else if(betrag < 0)
                    StatusLabel.setErrorText("Betrag ist negativ.");
                else
                {

                    /*-----------------------------
                     * Einzahlen veranlassen
                     * ----------------------------
                     */

                    try
                    {
                    	Account account = (Account) ObjectBroker.getBroker(host, port).getNameService().resolve(kontoID);

                        for (int i = 0; i < AnzSerienEinzahlung; i++)
                            account.deposit(betrag);

                        double bal = account.getBalance();

                        // Kontostandanzeige in GUI aktualisieren:
                        // KontostandTextField.setText(...);

                        KontostandTextField.setText(bal + "");

                        StatusLabel.setInfoText(DoneMessage);
                    }
                    catch (Exception e1)
                    {
                    	StatusLabel.setErrorText("Error: " + e1);
                    }
                }
            }
            catch (NumberFormatException e1)
            {
                StatusLabel.setErrorText("Ungueltiger Betrag!");
            }
        }
		else if (e.getSource() == AbhebenButton) {
			try {
				// Amount of the withdraw
				double betrag = Double.parseDouble(BetragsTextField.getText());
				
				//- Test of the Account field content
				String kontoID = KontoTextField.getText();
				if (kontoID == null || kontoID.equals("")) 
					StatusLabel.setErrorText("Kontofeld leer bzw. null");
				else {
					
					/*-----------------------------
					 * Abheben veranlassen
					 * ----------------------------
					 */
					
					try
                    {
                        Account account = (Account) ObjectBroker.getBroker(host, port).getNameService().resolve(kontoID);

                        account.withdraw(betrag);

                        double bal = account.getBalance();

                        // Kontostandanzeige in GUI aktualisieren:
                        KontostandTextField.setText(bal + "");

                        StatusLabel.setInfoText(DoneMessage);
                    }
                    catch (Exception exc)
                    {
                    	StatusLabel.setErrorText("Error");
                    }
				}
			} catch (NumberFormatException e1) {
				StatusLabel.setErrorText("Ungültiger Betrag!");				
			}
			
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		args=new String[2];
//		args[0]="localhost";
//		args[1]="1777";
		
		String regEx = "([a-zA-Z0-9 \t\\.\\-]*)";
		String regExPort = "([0-9]*)";
		if (args.length>0 && !args[0].equals("--help")
				&& args[0].matches(regEx) && args[1].matches(regExPort)) {
			Geldautomat kundenDienst = new Geldautomat(args[0],Integer.parseInt(args[1]));
			kundenDienst.setVisible(true);		
		} else {
			System.err.println("Usage: java geldautomat.Geldautomat <name-service-host> <name-service-port>");
			System.err.println("Host must contain only the characters 'A'...'Z','a'...'z','1'...'9','.','-' and Blanks");
			System.err.println("Port must contain only the characters '1'...'9'");
		}
	}

}
